---
description:
  Control and customize GraphQL schema built from REST service requests/responses using GraphQL Mesh
  JSON Schema handler. Learn more.
---

import { Callout } from '@theguild/components'

# JSON Schema or Samples

This handler allows you to load any remote REST service and describe its request/response using the
YAML config.

You can easily customize and control the built GraphQL schema with this handler.

## How to use?

To get started, install the handler library:

```sh npm2yarn
npm i @omnigraph/json-schema
```

Now, you can use it directly in your Mesh config file:

```ts filename="mesh.config.ts" {2,7-18}
import { defineConfig } from '@graphql-mesh/compose-cli'
import { loadJSONSchemaSubgraph } from '@omnigraph/json-schema'

export const composeConfig = defineConfig({
  subgraphs: [
    {
      sourceHandler: loadJSONSchemaSubgraph('MyApi', {
        endpoint: 'https://some-service-url/endpoint-path/',
        operations: [
          {
            type: 'Query',
            field: 'users',
            path: '/users',
            method: 'GET',
            responseSchema: './json-schemas/users.json'
          }
        ]
      })
    }
  ]
})
```

<Callout>
  [You can find a working example
  here](https://github.com/ardatan/graphql-mesh/tree/main/examples/v1-next/json-schema-example)
</Callout>

## Headers

[Read about configuration and examples](/docs/guides/headers)

### From Arguments

Mesh automatically generates arguments for operations if needed;

```ts filename="mesh.config.ts" {13}
import { defineConfig } from '@graphql-mesh/compose-cli'
import { loadJSONSchemaSubgraph } from '@omnigraph/json-schema'

export const composeConfig = defineConfig({
  subgraphs: [
    {
      sourceHandler: loadJSONSchemaSubgraph('MyApi', {
        endpoint: 'https://some-service-url/endpoint-path/',
        operations: [
          {
            type: 'Query',
            field: 'user',
            path: '/user/{args.id}',
            method: 'GET',
            responseSchema: './json-schemas/user.json'
          }
        ]
      })
    }
  ]
})
```

This example operation definition will generate a root field with `id: ID` argument. Mesh will
interpolate the expression in `path` to get `id` value from `args`.

### From JSON Samples

Mesh can also load JSON samples from a remote service. Add a `json-samples` directory in your
project root, and put the JSON samples there
(`responseSample: './jsons/MyField.response.json'{:ts}` - Create a new folder like `jsons`). By
declaring the `responseSample`, you can use the JSON sample in the GraphQL schema.

```ts filename="mesh.config.ts" {13}
import { defineConfig } from '@graphql-mesh/compose-cli'
import { loadJSONSchemaSubgraph } from '@omnigraph/json-schema'

export const composeConfig = defineConfig({
  subgraphs: [
    {
      sourceHandler: loadJSONSchemaSubgraph('MyApi', {
        endpoint: 'https://some-service-url/endpoint-path/',
        operations: [
          {
            type: 'Query',
            field: 'myField',
            path: '/myField?id={args.id}',
            method: 'GET',
            responseSample: './jsons/MyField.response.json',
            responseTypeName: 'MyResponseName',
            argTypeMap: {
              id: {
                type: 'string'
              }
            }
          }
        ]
      })
    }
  ]
})
```

```json filename="MyField.response.json"
Any JSON sample file can be used.
```

## Query Parameters

There are a few methods to define the query parameters, select the one that fits your needs (Or
combine them):

### Auto declare:

Mesh automatically generates arguments for operations if needed. Note that the arguments are
generated as nullable strings by default.

```ts filename="mesh.config.ts" {13}
import { defineConfig } from '@graphql-mesh/compose-cli'
import { loadJSONSchemaSubgraph } from '@omnigraph/json-schema'

export const composeConfig = defineConfig({
  subgraphs: [
    {
      sourceHandler: loadJSONSchemaSubgraph('MyApi', {
        endpoint: 'https://some-service-url/endpoint-path/',
        operations: [
          {
            type: 'Query',
            field: 'user',
            path: '/user?id={args.id}',
            method: 'GET',
            responseSchema: './json-schemas/user.json'
          }
        ]
      })
    }
  ]
})
```

### With Samples

You can use the JSON samples to define the query parameters.

In this example we declare `limit` and `offset` properties:

```ts filename="mesh.config.ts" {15}
import { defineConfig } from '@graphql-mesh/compose-cli'
import { loadJSONSchemaSubgraph } from '@omnigraph/json-schema'

export const composeConfig = defineConfig({
  subgraphs: [
    {
      sourceHandler: loadJSONSchemaSubgraph('MyApi', {
        endpoint: 'https://some-service-url/endpoint-path/',
        operations: [
          {
            type: 'Query',
            field: 'getUsers',
            path: '/users',
            method: 'GET',
            queryParamsSample: './jsons/users.queryParams.json',
            responseSchema: './jsons/users.response.json'
          }
        ]
      })
    }
  ]
})
```

In `./jsons/users.queryParams.json`:

```json filename="users.queryParams.json"
{
  "limit": 10,
  "offset": 0
}
```

### Manual Declare

You can define the arguments of the operation using the `argTypeMap` config field, according to the
JSON Schema spec.

`type: number` will set the property to `Float` and `type: integer` will set it as Int.

In this example we declare `page` argument as an object with `limit` and `offset` properties:

```ts
argTypeMap: {
  page: {
    type: 'object',
    properties: {
      limit: {
        type: 'integer'
      },
      offset: {
        type: 'integer'
      }
    }
  }
}
```

Array can be defined as `type: array` with `items:` and their own `type:`

```ts
argTypeMap: {
  page: {
    type: 'array',
    items: {
      limit: {
        type: 'integer'
      },
      offset: {
        type: 'integer'
      }
    }
  }
}
```

If you need to use symbols that will cause GraphQL to error like ':' or '[' in the query param name,
you can map an alternative definition. With the below example using `name_like` in the query will
end up being `name:like` as the API call.

```ts
argTypeMap: {
  name_like: {
    type: 'string'
  }
  queryParamArgMap: {
    'name:like': 'name_like'
  }
}
```

In addition, especially for non-primitive types, the arguments should be added to the path using the
`queryParamArgMap` config field.

Here we add the `page` argument to the query parameters:

```ts
queryParamArgMap: {
  page: 'page'
}
```

And here is the final config:

```ts filename="mesh.config.ts" {17-33}
import { defineConfig } from '@graphql-mesh/compose-cli'
import { loadJSONSchemaSubgraph } from '@omnigraph/json-schema'

export const composeConfig = defineConfig({
  subgraphs: [
    {
      sourceHandler: loadJSONSchemaSubgraph('MyApi', {
        endpoint: 'https://some-service-url/endpoint-path/',
        operations: [
          {
            type: 'Query',
            field: 'getUsers',
            path: '/users',
            method: 'GET',
            responseSample: './jsons/users.response.json',
            responseTypeName: 'MyResponseName',
            argTypeMap: {
              page: {
                type: 'object',
                properties: {
                  limit: {
                    type: 'integer'
                  },
                  offset: {
                    type: 'integer'
                  }
                }
              }
            },
            queryParamArgMap: {
              page: 'page'
            }
          }
        ]
      })
    }
  ]
})
```

### Global Arguments

Query arguments could be defined globally, on handler level, so they are added to all operations.

In this example we declare `limit` parameter with the default value of `10`, and `api_key` with
dynamic value taken from the environment:

```ts filename="mesh.config.ts" {12-15}
import { defineConfig } from '@graphql-mesh/compose-cli'
import { loadJSONSchemaSubgraph } from '@omnigraph/json-schema'

export const composeConfig = defineConfig({
  subgraphs: [
    {
      sourceHandler: loadJSONSchemaSubgraph('MyApi', {
        endpoint: 'https://some-service-url/endpoint-path/',
        operations: [
          // Operations here
        ],
        queryParams: {
          limit: 10,
          api_key: '{env.MY_API_KEY}'
        }
      })
    }
  ]
})
```

<Callout>
  Note that `queryParams` are automatically added to the query. If argument is defined both on
  handler AND operation level, the operation level argument will be used.
</Callout>
